#ifndef DEP_HPP
#define DEP_HPP

#include"common.hpp"

class Node;
class Value;
class Dep;
class RegValue;



class Dep{
	friend class Node;
	friend struct _flag_mask;

public:
	enum DEP_TAG  {OUTD = 0, IND = 1};//for DIter implement
	template< enum DEP_TAG > friend class _DIter;
	template<enum DEP_TAG> friend class Dep_Sequence;
/*
 * =====================================================
 * 	intrusive link list 
 *  the purpose for the designment of intrusive link list  
 *  is the diter  which have the function of  filter 
 *  The instrusive link list facilitate the filter iterator 
 *  operation
 * =====================================================
 */
private:
	static void insert_out_after(Dep* out_deps, Dep * new_dep );
	static void insert_in_after(Dep * in_deps, Dep * new_dep);

	Dep * next[2];

/*
 * ==========================================================
 * 		for Dependence information
 *
 * ==========================================================
 */
private:
	enum DType type_flag;
	int value_id;
	int weight;

	Node * from;
	location from_loc;
   	Node * to;
	location to_loc;

  	bool visited;
public:
	void set_weight(int x){ weight = x;}
	void set_type_flag(enum DType  flag) { type_flag = flag;}
	//now ,to get a dep must call friend class DAG::new_dep(...);
   	Dep(Node &from, location from_loc, Node & to, location to_loc);

    	RegValue* get_to_value();
    	RegValue* get_from_value();
	bool is_visited()const;
	void set_visisted();
	void reset_visited();
	const location & get_from_loc()const {return from_loc;}
	const location & get_to_loc()const{ return to_loc;}
	unsigned int get_type_flag()const {return type_flag;}

	int get_value_id()const {return value_id;}

	Node * get_from_node()const {return from;}
	Node * get_to_node() const { return to;}
	int get_weight() const {return weight;}

	std::string get_dep_name()const;
	static enum DType get_dep_type(enum LOC_Type from, enum LOC_Type to);
	void print();
};

template<enum  Dep::DEP_TAG in_or_out >
class _DIter{
	Dep * cur;
	unsigned int flags;
public:
	_DIter(Dep * dep, unsigned int flag ):cur(dep), flags(flag)
	{

	}
	inline bool is_end()
	{
		if(cur == NULL)
			return true;
		else 
			return false;
	}
	inline void operator ++ (int)
	{
		while(cur && !(cur->type_flag & flags))
		{
			cur = cur->next[in_or_out];
		}
	}
	inline Dep * operator ->()
	{
		return cur;
	}
	inline Dep& operator *()
	{
		return *cur;
	}
};


typedef _DIter<Dep::OUTD> ODIter;
typedef _DIter<Dep::IND> IDIter;

template< enum Dep::DEP_TAG tag>
class Dep_Sequence{
	Dep * header;	
public:
	void add(Dep *);
	void remove(Dep *);//not delete the dep 	
	_DIter<tag> begin(unsigned int )const;
};

template<enum Dep::DEP_TAG tag>  
_DIter<tag>  Dep_Sequence<tag>::begin( unsigned int flag)const
{
	Dep * t = header;
	while( t != NULL && !(t->type_flag & flag))
	{
		t = t->next[tag];	
	}
	return _DIter<tag>(t, flag);
}

template<enum Dep::DEP_TAG tag>
void Dep_Sequence<tag>::add(Dep * d)
{
	d->next[tag] = header;
	header = d;
}

template<enum Dep::DEP_TAG tag>
void Dep_Sequence<tag>::remove(Dep * d)
{
	Dep * t = header;
	while(t != NULL && t->next[tag] != d)
	{
		t = t->next[tag];
	}
	assert(t != NULL);
	assert(d != NULL);
	t->next[tag] = d->next[tag]; 
}

#endif
